﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using JelleDruyts.Windows;
using Schedulr.Infrastructure;
using Schedulr.Models;

namespace Schedulr.Providers
{
    public static class PictureProvider
    {
        #region GetPicture

        /// <summary>
        /// Gets the picture information for a picture file.
        /// </summary>
        /// <param name="fileName">The full path to the picture file.</param>
        /// <param name="retrieveMetadata">Determines if an attempt should be made to retrieve picture metadata from the file.</param>
        /// <param name="pictureDefaults">The defaults for the picture.</param>
        /// <returns>The picture information for the given path.</returns>
        public static Picture GetPicture(string fileName, bool retrieveMetadata, Picture pictureDefaults)
        {
            if (!File.Exists(fileName))
            {
                throw new ArgumentException("The specified file does not exist: " + fileName);
            }

            Picture picture;
            if (pictureDefaults != null)
            {
                picture = SerializationProvider.Clone<Picture>(pictureDefaults);
            }
            else
            {
                picture = new Picture();
            }
            picture.FileName = fileName;

            // Only set the title to the file name if no default title was present.
            if (string.IsNullOrWhiteSpace(picture.Title))
            {
                picture.Title = Path.GetFileNameWithoutExtension(fileName);
            }

            // Always clear some properties.
            picture.BatchId = 0;
            picture.DateUploaded = null;

            if (retrieveMetadata)
            {
                // Try to get the metadata we need.
                try
                {
                    Logger.Log("Retrieving metadata from picture " + fileName, TraceEventType.Verbose);
                    string fileContents = null;
                    using (var reader = new StreamReader(fileName))
                    {
                        fileContents = reader.ReadToEnd();
                    }
                    const string beginCapture = "<rdf:RDF";
                    const string endCapture = "</rdf:RDF>";
                    var beginPos = fileContents.IndexOf(beginCapture, StringComparison.OrdinalIgnoreCase);
                    var endPos = fileContents.IndexOf(endCapture, StringComparison.OrdinalIgnoreCase);
                    if (beginPos >= 0 && endPos > beginPos)
                    {
                        var xmlPart = fileContents.Substring(beginPos, (endPos - beginPos) + endCapture.Length);
                        RetrieveMetadata(xmlPart, picture);
                    }
                    else
                    {
                        Logger.Log("Could not retrieve metadata from picture " + fileName, TraceEventType.Verbose);
                    }
                }
                catch (Exception exc)
                {
                    Logger.Log("Could not retrieve metadata from picture " + fileName, exc);
                }
            }
            return picture;
        }

        #endregion

        #region RetrieveMetadata

        /// <summary>
        /// Retrieves the meta data.
        /// </summary>
        /// <param name="embeddedMetadataXml">The embedded meta data XML.</param>
        /// <param name="picture">The picture.</param>
        private static void RetrieveMetadata(string embeddedMetadataXml, Picture picture)
        {
            // Thank you Omar: http://www.shahine.com/omar/ReadingXMPMetadataFromAJPEGUsingC.aspx.
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(embeddedMetadataXml);

            XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
            nsMgr.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            nsMgr.AddNamespace("exif", "http://ns.adobe.com/exif/1.0/");
            nsMgr.AddNamespace("x", "adobe:ns:meta/");
            nsMgr.AddNamespace("xap", "http://ns.adobe.com/xap/1.0/");
            nsMgr.AddNamespace("tiff", "http://ns.adobe.com/tiff/1.0/");
            nsMgr.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");

            // get keywords
            XmlNode xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:subject/rdf:Bag", nsMgr);
            if (xmlNode != null)
            {
                StringBuilder tags = new StringBuilder();
                foreach (XmlNode tagNode in xmlNode)
                {
                    if (tags.Length > 0)
                    {
                        // Separate tags with spaces.
                        tags.Append(" ");
                    }
                    string tag = tagNode.InnerText;
                    if (tag.Contains(" "))
                    {
                        // If the tag contains spaces, put double quotes around them.
                        tag = string.Format(CultureInfo.CurrentCulture, "\"{0}\"", tag);
                    }
                    tags.Append(tag);
                }
                picture.Tags = tags.ToString();
            }

            // get title
            xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:title/rdf:Alt", nsMgr);
            if (xmlNode != null && xmlNode.ChildNodes.Count > 0)
            {
                picture.Title = xmlNode.ChildNodes[0].InnerText;
            }

            // get description
            xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:description/rdf:Alt", nsMgr);
            if (xmlNode != null && xmlNode.ChildNodes.Count > 0)
            {
                picture.Description = xmlNode.ChildNodes[0].InnerText;
            }
        }

        #endregion
    }
}